using System;
using System.Text;

namespace tar_cs
{
	internal class TarHeader : ITarHeader
	{
		private readonly byte[] buffer = new byte[512];

		private long headerChecksum;

		private string fileName;

		protected readonly DateTime TheEpoch = new DateTime(1970, 1, 1, 0, 0, 0);

		private static byte[] spaces = Encoding.UTF8.GetBytes("        ");

		public EntryType EntryType { get; set; }

		public virtual string FileName
		{
			get
			{
				return fileName.Replace("\0", string.Empty);
			}
			set
			{
				if (value.Length > 100)
				{
					throw new TarException("A file name can not be more than 100 chars long");
				}
				fileName = value;
			}
		}

		public int Mode { get; set; }

		public string ModeString
		{
			get
			{
				return Convert.ToString(Mode, 8).PadLeft(7, '0');
			}
		}

		public int UserId { get; set; }

		public virtual string UserName
		{
			get
			{
				return UserId.ToString();
			}
			set
			{
				UserId = int.Parse(value);
			}
		}

		public string UserIdString
		{
			get
			{
				return Convert.ToString(UserId, 8).PadLeft(7, '0');
			}
		}

		public int GroupId { get; set; }

		public virtual string GroupName
		{
			get
			{
				return GroupId.ToString();
			}
			set
			{
				GroupId = int.Parse(value);
			}
		}

		public string GroupIdString
		{
			get
			{
				return Convert.ToString(GroupId, 8).PadLeft(7, '0');
			}
		}

		public long SizeInBytes { get; set; }

		public string SizeString
		{
			get
			{
				return Convert.ToString(SizeInBytes, 8).PadLeft(11, '0');
			}
		}

		public DateTime LastModification { get; set; }

		public string LastModificationString
		{
			get
			{
				return Convert.ToString((long)(LastModification - TheEpoch).TotalSeconds, 8).PadLeft(11, '0');
			}
		}

		public string HeaderChecksumString
		{
			get
			{
				return Convert.ToString(headerChecksum, 8).PadLeft(6, '0');
			}
		}

		public virtual int HeaderSize
		{
			get
			{
				return 512;
			}
		}

		public TarHeader()
		{
			Mode = 511;
			UserId = 61;
			GroupId = 61;
		}

		public static long NetworkToHostOrder(long network)
		{
			return network;
		}

		public static long HostToNetworkOrder(long host)
		{
			return host;
		}

		public byte[] GetBytes()
		{
			return buffer;
		}

		public virtual bool UpdateHeaderFromBytes()
		{
			FileName = Encoding.UTF8.GetString(buffer, 0, 100);
			Mode = Convert.ToInt32(Encoding.UTF8.GetString(buffer, 100, 7).Trim(), 8);
			UserId = Convert.ToInt32(Encoding.UTF8.GetString(buffer, 108, 7).Trim(), 8);
			GroupId = Convert.ToInt32(Encoding.UTF8.GetString(buffer, 116, 7).Trim(), 8);
			EntryType = (EntryType)buffer[156];
			if ((buffer[124] & 0x80) == 128)
			{
				long network = BitConverter.ToInt64(buffer, 128);
				SizeInBytes = NetworkToHostOrder(network);
			}
			else
			{
				SizeInBytes = Convert.ToInt64(Encoding.UTF8.GetString(buffer, 124, 11), 8);
			}
			long num = Convert.ToInt64(Encoding.UTF8.GetString(buffer, 136, 11), 8);
			LastModification = TheEpoch.AddSeconds(num);
			int num2 = Convert.ToInt32(Encoding.UTF8.GetString(buffer, 148, 6));
			RecalculateChecksum(buffer);
			if (num2 == headerChecksum)
			{
				return true;
			}
			RecalculateAltChecksum(buffer);
			return num2 == headerChecksum;
		}

		private void RecalculateAltChecksum(byte[] buf)
		{
			spaces.CopyTo(buf, 148);
			headerChecksum = 0L;
			foreach (byte b in buf)
			{
				if ((b & 0x80) == 128)
				{
					headerChecksum -= b ^ 0x80;
				}
				else
				{
					headerChecksum += (int)b;
				}
			}
		}

		public virtual byte[] GetHeaderValue()
		{
			Array.Clear(buffer, 0, buffer.Length);
			if (string.IsNullOrEmpty(FileName))
			{
				throw new TarException("FileName can not be empty.");
			}
			if (FileName.Length >= 100)
			{
				throw new TarException("FileName is too long. It must be less than 100 bytes.");
			}
			Encoding.UTF8.GetBytes(FileName.PadRight(100, '\0')).CopyTo(buffer, 0);
			Encoding.UTF8.GetBytes(ModeString).CopyTo(buffer, 100);
			Encoding.UTF8.GetBytes(UserIdString).CopyTo(buffer, 108);
			Encoding.UTF8.GetBytes(GroupIdString).CopyTo(buffer, 116);
			Encoding.UTF8.GetBytes(SizeString).CopyTo(buffer, 124);
			Encoding.UTF8.GetBytes(LastModificationString).CopyTo(buffer, 136);
			buffer[156] = (byte)EntryType;
			RecalculateChecksum(buffer);
			Encoding.UTF8.GetBytes(HeaderChecksumString).CopyTo(buffer, 148);
			return buffer;
		}

		protected virtual void RecalculateChecksum(byte[] buf)
		{
			spaces.CopyTo(buf, 148);
			headerChecksum = 0L;
			foreach (byte b in buf)
			{
				headerChecksum += (int)b;
			}
		}
	}
}
